#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
双重量能验证器

设计原则：
1. 第一重（量比）：快速筛选，基于短期量能变化
2. 第二重（20日均量）：深度验证，基于长期量能基准
3. 只对需要验证的情况（放量、温和放量）进行20日均量检查
4. 时间感知：考虑盘中不同时段的成交量累积特性
"""

import numpy as np
from datetime import datetime
import logging

logger = logging.getLogger(__name__)


class DoubleVolumeValidator:
    """双重量能验证器"""
    
    def __init__(self, config):
        """
        初始化验证器
        
        Args:
            config: 配置字典，包含double_volume_validation配置
        """
        self.config = config.get('double_volume_validation', {})
        self.enabled = self.config.get('enabled', True)
        
        # 第一重：量比分类阈值
        self.volume_ratio_thresholds = self.config.get('volume_ratio_thresholds', {
            'large_cap': [2.2, 1.5, 0.8, 0.5],
            'mid_cap': [2.5, 1.8, 0.9, 0.6],
            'small_cap': [3.0, 2.0, 1.0, 0.7]
        })
        
        # 第二重：20日均量基础阈值
        self.base_20day_thresholds = self.config.get('base_20day_thresholds', {
            'large_cap': 1.0,
            'mid_cap': 1.2,
            'small_cap': 1.5
        })
        
        # 时间调整因子
        self.time_factors = self.config.get('time_factors', {
            'morning_early': 0.3,
            'morning_mid': 0.6,
            'morning_late': 0.8,
            'afternoon_early': 0.9,
            'afternoon_late': 1.0
        })
        
        # 第三重：量能趋势验证
        self.enable_trend_check = self.config.get('enable_trend_check', False)
        self.trend_thresholds = self.config.get('trend_thresholds', {
            'ma5_vs_ma10': 0.9,  # MA5 >= MA10 * 0.9
            'ma10_vs_ma20': 0.85  # MA10 >= MA20 * 0.85
        })
        
        # 市场环境动态调整
        self.enable_market_adjustment = self.config.get('enable_market_adjustment', False)
        self.market_thresholds = self.config.get('market_thresholds', {
            'bull_change': 2.0,   # 大盘涨幅>2%认为牛市
            'bear_change': -2.0,  # 大盘跌幅<-2%认为熊市
            'bull_factor': 0.9,   # 牛市放宽10%
            'bear_factor': 1.1    # 熊市提高10%
        })
    
    def validate_volume_conditions(self, stock_data, market_cap_type, current_time=None, 
                                   market_environment=None):
        """
        双重量能验证系统
        
        Args:
            stock_data: 股票数据字典，包含：
                - volume: 当前成交量
                - volume_ma5: 5日均量
                - volume_ma10: 10日均量（可选，用于第三重）
                - volume_ma20: 20日均量
                - volumes: 历史成交量数组（可选，用于第三重）
            market_cap_type: 市值类型 ('large_cap', 'mid_cap', 'small_cap')
            current_time: 当前时间（datetime对象），用于时间因子计算
            market_environment: 市场环境数据（可选），用于动态调整
        
        Returns:
            dict: {
                'passed': bool,           # 是否通过验证
                'volume_status': str,     # 量能状态
                'message': str,           # 详细信息
                'details': dict          # 详细验证数据
            }
        """
        if not self.enabled:
            return {
                'passed': True,
                'volume_status': 'unknown',
                'message': '验证功能未启用',
                'details': {}
            }
        
        # 第一重：量比分类
        volume_status = self._classify_volume_status(stock_data, market_cap_type)
        
        # 初始化返回结果
        result = {
            'passed': True,
            'volume_status': volume_status,
            'message': '',
            'details': {
                'first_layer': f'量比分类: {volume_status}',
                'second_layer': None,
                'third_layer': None,
                'market_adjustment': None
            }
        }
        
        # 第二重：20日均量验证（仅对放量和温和放量）
        if volume_status in ["放量", "温和放量"]:
            validation_passed, message, details = self._check_20_day_volume(
                stock_data, market_cap_type, current_time, market_environment
            )
            
            result['passed'] = validation_passed
            result['message'] = f"{volume_status} | {message}"
            result['details']['second_layer'] = message
            result['details']['second_layer_details'] = details
            
            if not validation_passed:
                return result
        else:
            result['message'] = f"{volume_status} | 无需20日均量验证"
            result['details']['second_layer'] = '无需20日均量验证'
        
        # 第三重：量能趋势验证（可选）
        if self.enable_trend_check and 'volumes' in stock_data:
            trend_passed, trend_message = self._check_volume_trend(stock_data)
            result['details']['third_layer'] = trend_message
            
            if not trend_passed:
                result['passed'] = False
                result['message'] += f" | 量能趋势: {trend_message}"
        
        return result
    
    def _classify_volume_status(self, stock_data, market_cap_type):
        """
        第一重：量比分类
        
        Args:
            stock_data: 股票数据
            market_cap_type: 市值类型
        
        Returns:
            str: 量能状态
        """
        current_volume = stock_data.get('volume', 0)
        volume_ma5 = stock_data.get('volume_ma5', 1)
        
        if volume_ma5 <= 0:
            return "未知"
        
        volume_ratio = current_volume / volume_ma5
        
        # 获取差异化阈值
        thresholds = self.volume_ratio_thresholds.get(market_cap_type, 
                     self.volume_ratio_thresholds['mid_cap'])
        
        heavy, moderate, normal, mild = thresholds
        
        if volume_ratio >= heavy:
            return "放量"
        elif volume_ratio >= moderate:
            return "温和放量"
        elif volume_ratio >= normal:
            return "正常量"
        elif volume_ratio >= mild:
            return "温和缩量"
        else:
            return "缩量"
    
    def _check_20_day_volume(self, stock_data, market_cap_type, current_time=None, 
                            market_environment=None):
        """
        第二重：20日均量验证
        
        Args:
            stock_data: 股票数据
            market_cap_type: 市值类型
            current_time: 当前时间
            market_environment: 市场环境数据
        
        Returns:
            tuple: (是否通过, 消息, 详细数据)
        """
        current_volume = stock_data.get('volume', 0)
        volume_ma20 = stock_data.get('volume_ma20', 1)
        
        if volume_ma20 <= 0:
            return False, "20日均量数据无效", {}
        
        # 基础阈值
        base_threshold = self.base_20day_thresholds.get(market_cap_type, 1.2)
        
        # 时间因子
        time_factor = self._get_time_factor(current_time) if current_time else 1.0
        
        # 市场环境因子（可选）
        market_factor = 1.0
        if self.enable_market_adjustment and market_environment:
            market_factor = self._get_market_environment_factor(market_environment)
        
        # 计算最终调整后阈值
        adjusted_threshold = base_threshold * time_factor * market_factor
        required_volume = volume_ma20 * adjusted_threshold
        
        # 验证
        passed = current_volume >= required_volume
        
        # 构建消息
        time_str = current_time.strftime('%H:%M') if current_time else '全天'
        message = (f"20日均量验证{'通过' if passed else '失败'} | "
                  f"时间{time_str} | "
                  f"实际{self._format_volume(current_volume)} vs "
                  f"要求{self._format_volume(required_volume)}")
        
        # 详细数据
        details = {
            'current_volume': current_volume,
            'volume_ma20': volume_ma20,
            'base_threshold': base_threshold,
            'time_factor': time_factor,
            'market_factor': market_factor,
            'adjusted_threshold': adjusted_threshold,
            'required_volume': required_volume,
            'passed': passed
        }
        
        return passed, message, details
    
    def _check_volume_trend(self, stock_data):
        """
        第三重：量能趋势验证（可选）
        确保量能不是持续萎缩的
        
        Args:
            stock_data: 股票数据，需要包含volumes数组
        
        Returns:
            tuple: (是否通过, 消息)
        """
        volumes = stock_data.get('volumes')
        if volumes is None or len(volumes) < 20:
            return True, "数据不足，跳过趋势验证"
        
        # 计算均量
        vol_ma5 = float(np.mean(volumes[-5:]))
        vol_ma10 = float(np.mean(volumes[-10:]))
        vol_ma20 = float(np.mean(volumes[-20:]))
        
        # 阈值
        ma5_threshold = self.trend_thresholds['ma5_vs_ma10']
        ma10_threshold = self.trend_thresholds['ma10_vs_ma20']
        
        # 量能呈现上升趋势
        ma5_ok = vol_ma5 >= vol_ma10 * ma5_threshold
        ma10_ok = vol_ma10 >= vol_ma20 * ma10_threshold
        
        if ma5_ok and ma10_ok:
            return True, f"量能趋势向上(MA5>{vol_ma5:.0f} MA10>{vol_ma10:.0f} MA20>{vol_ma20:.0f})"
        else:
            reasons = []
            if not ma5_ok:
                reasons.append(f"MA5({vol_ma5:.0f})<MA10×{ma5_threshold}({vol_ma10*ma5_threshold:.0f})")
            if not ma10_ok:
                reasons.append(f"MA10({vol_ma10:.0f})<MA20×{ma10_threshold}({vol_ma20*ma10_threshold:.0f})")
            return False, f"量能趋势走弱({', '.join(reasons)})"
    
    def _get_time_factor(self, current_time):
        """
        获取时间调整因子
        
        Args:
            current_time: datetime对象
        
        Returns:
            float: 时间因子
        """
        if current_time is None:
            return 1.0
        
        hour = current_time.hour
        minute = current_time.minute
        time_key = hour * 100 + minute
        
        # 根据时间段返回因子
        if time_key < 1000:  # 09:30-10:00
            return self.time_factors['morning_early']
        elif time_key < 1100:  # 10:00-11:00
            return self.time_factors['morning_mid']
        elif time_key < 1130:  # 11:00-11:30
            return self.time_factors['morning_late']
        elif time_key < 1400:  # 13:00-14:00
            return self.time_factors['afternoon_early']
        else:  # 14:00-15:00
            return self.time_factors['afternoon_late']
    
    def _get_market_environment_factor(self, market_environment):
        """
        根据市场环境动态调整阈值
        
        Args:
            market_environment: dict, 包含：
                - index_change_pct: 大盘涨跌幅
                - volume_ratio: 大盘量比（可选）
        
        Returns:
            float: 市场因子
        """
        change_pct = market_environment.get('index_change_pct', 0)
        
        bull_threshold = self.market_thresholds['bull_change']
        bear_threshold = self.market_thresholds['bear_change']
        
        if change_pct >= bull_threshold:
            # 牛市环境，放宽要求
            return self.market_thresholds['bull_factor']
        elif change_pct <= bear_threshold:
            # 熊市环境，提高要求
            return self.market_thresholds['bear_factor']
        else:
            # 正常市场
            return 1.0
    
    @staticmethod
    def _format_volume(volume):
        """格式化成交量显示"""
        if volume >= 100000000:  # 亿
            return f"{volume/100000000:.2f}亿手"
        elif volume >= 10000:  # 万
            return f"{volume/10000:.0f}万手"
        else:
            return f"{volume:.0f}手"

